package com.weijian.service.impl;

import com.weijian.common.ApiResponse;
import com.weijian.common.BusinessException;
import com.weijian.dal.entity.User;
import com.weijian.dal.enums.UserStatus;
import com.weijian.dal.dto.user.UserLoginRequest;
import com.weijian.dal.dto.user.UserRegisterRequest;
import com.weijian.dal.mapper.UserMapper;
import com.weijian.service.UserService;
import com.weijian.util.RedisKeyUtil;
import com.weijian.util.SessionUserUtil;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.concurrent.TimeUnit;

/**
 * 用户服务实现类
 *
 * @author weijian
 * @since 2024-12-20
 */
@Service
@Slf4j
public class UserServiceImpl implements UserService {

    @Resource
    private UserMapper userMapper;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Resource
    private PasswordEncoder passwordEncoder;

    /**
     * 用户信息缓存时间：30分钟
     */
    private static final long USER_CACHE_TTL = 30 * 60;

    /**
     * 会话缓存时间：7天（记住我）或30分钟（普通登录）
     */
    private static final long SESSION_REMEMBER_TTL = 7 * 24 * 60 * 60;
    private static final long SESSION_NORMAL_TTL = 30 * 60;

    /**
     * 登录失败最大重试次数
     */
    private static final int MAX_LOGIN_FAILS = 5;

    /**
     * 登录失败锁定时间：30分钟
     */
    private static final long LOGIN_FAIL_LOCK_TTL = 30 * 60;

    @Override
    public ApiResponse<User> register(UserRegisterRequest registerRequest) {
        // 参数校验
        if (!StringUtils.hasText(registerRequest.getUsername())) {
            return ApiResponse.badRequest("用户名不能为空");
        }
        if (!StringUtils.hasText(registerRequest.getEmail())) {
            return ApiResponse.badRequest("邮箱不能为空");
        }
        if (!StringUtils.hasText(registerRequest.getPassword())) {
            return ApiResponse.badRequest("密码不能为空");
        }
        if (!registerRequest.getPassword().equals(registerRequest.getConfirmPassword())) {
            return ApiResponse.badRequest("两次输入的密码不一致");
        }

        // 检查用户名唯一性
        if (userMapper.existsByUsername(registerRequest.getUsername())) {
            return ApiResponse.badRequest("用户名已存在");
        }

        // 检查邮箱唯一性
        if (userMapper.existsByEmail(registerRequest.getEmail())) {
            return ApiResponse.badRequest("邮箱已被注册");
        }

        // 检查手机号唯一性
        if (userMapper.existsByPhone(registerRequest.getPhone())) {
            return ApiResponse.badRequest("手机号已被注册");
        }

        try {
            // 创建用户实体
            User user = User.builder()
                    .username(registerRequest.getUsername())
                    .email(registerRequest.getEmail())
                    .phone(registerRequest.getPhone())
                    .password(passwordEncoder.encode(registerRequest.getPassword()))
                    .avatar("/default-avatar.png")
                    .status(UserStatus.ACTIVE)
                    .build();

            // 保存到数据库
            userMapper.insert(user);

            // 缓存用户信息
            cacheUserInfo(user);

            return ApiResponse.success("注册成功", user);

        } catch (Exception e) {
            log.error("注册异常: {}", e.getMessage(), e);
            throw new BusinessException("注册失败，请稍后重试");
        }
    }

    @Override
    public ApiResponse<User> login(UserLoginRequest loginRequest, HttpServletResponse response) {
        String usernameOrEmail = loginRequest.getUsernameOrEmail();

        // 检查是否被锁定
        if (isLoginLocked(usernameOrEmail)) {
            return ApiResponse.badRequest("登录失败次数过多，请30分钟后再试");
        }

        try {
            // 查询用户
            User user = findUserByUsernameOrEmail(usernameOrEmail);
            if (user == null) {
                incrementLoginFail(usernameOrEmail);
                return ApiResponse.badRequest("用户名或密码错误");
            }

            // 检查用户状态
            if (user.getStatus() != UserStatus.ACTIVE) {
                return ApiResponse.badRequest("账户已被禁用");
            }

            // 验证密码
            if (!passwordEncoder.matches(loginRequest.getPassword(), user.getPassword())) {
                incrementLoginFail(usernameOrEmail);
                return ApiResponse.badRequest("用户名或密码错误");
            }

            // 清除登录失败计数
            clearLoginFail(usernameOrEmail);

            // 创建会话 - 使用Spring Session
            SessionUserUtil.setCurrentUser(user, loginRequest.isRememberMe() ? SESSION_REMEMBER_TTL : SESSION_NORMAL_TTL);

            return ApiResponse.success("登录成功", user);

        } catch (Exception e) {
            log.error("登录异常: {}", e.getMessage(), e);
            throw new BusinessException("登录失败，请稍后重试");
        }
    }

    @Override
    public ApiResponse<Void> logout(HttpServletRequest request, HttpServletResponse response) {
        // 清除当前用户会话
        SessionUserUtil.clearCurrentUser();
        return ApiResponse.success("登出成功");
    }

    @Override
    public ApiResponse<User> getCurrentUser(HttpServletRequest request) {
        User user = SessionUserUtil.getCurrentUser();
        if (user == null) {
            return ApiResponse.unauthorized("未登录");
        }
        return ApiResponse.success(user);
    }

    @Override
    public ApiResponse<User> getUserById(Long userId) {
        // 先从缓存中获取
        String key = RedisKeyUtil.getUserInfoKey(userId);
        User user = (User) redisTemplate.opsForValue().get(key);

        if (user == null) {
            // 缓存未命中，查询数据库
            user = userMapper.selectById(userId);
            if (user != null) {
                cacheUserInfo(user);
            }
        }

        if (user == null || user.getStatus() != UserStatus.ACTIVE) {
            return ApiResponse.notFound("用户不存在");
        }

        return ApiResponse.success(user);
    }

    @Override
    public boolean isLoggedIn(HttpServletRequest request) {
        return SessionUserUtil.getCurrentUser() != null;
    }

    @Override
    public ApiResponse<Void> deleteAccount(String password, HttpServletRequest request) {
        // 获取当前用户
        User currentUser = SessionUserUtil.getCurrentUser();
        if (currentUser == null) {
            return ApiResponse.unauthorized("未登录");
        }

        try {
            // 验证密码
            if (!passwordEncoder.matches(password, currentUser.getPassword())) {
                return ApiResponse.badRequest("密码错误");
            }

            // 清除用户相关缓存
            clearUserCache(currentUser.getId());

            // 清除当前会话
            SessionUserUtil.clearCurrentUser();

            // 逻辑删除用户（软删除）
            currentUser.setStatus(UserStatus.DELETED);
            userMapper.updateById(currentUser);

            log.info("用户账号已注销: {}", currentUser.getUsername());
            return ApiResponse.success("账号已成功注销");

        } catch (Exception e) {
            log.error("注销账号异常: {}", e.getMessage(), e);
            throw new BusinessException("注销账号失败，请稍后重试");
        }
    }

    /**
     * 根据用户名或邮箱查找用户
     */
    private User findUserByUsernameOrEmail(String usernameOrEmail) {
        if (usernameOrEmail.contains("@")) {
            return userMapper.selectByEmail(usernameOrEmail);
        } else {
            return userMapper.selectByUsername(usernameOrEmail);
        }
    }

    /**
     * 缓存用户信息
     */
    private void cacheUserInfo(User user) {
        String key = RedisKeyUtil.getUserInfoKey(user.getId());
        redisTemplate.opsForValue().set(key, user, USER_CACHE_TTL, TimeUnit.SECONDS);
    }

    /**
     * 清除用户相关缓存
     */
    private void clearUserCache(Long userId) {
        // 清除用户信息缓存
        String userInfoKey = RedisKeyUtil.getUserInfoKey(userId);
        redisTemplate.delete(userInfoKey);

        // 可以在这里添加更多需要清除的缓存
        log.debug("用户缓存已清除: {}", userId);
    }

    /**
     * 检查登录是否被锁定
     */
    private boolean isLoginLocked(String usernameOrEmail) {
        String key = RedisKeyUtil.getLoginFailKey(usernameOrEmail);
        Integer failCount = (Integer) redisTemplate.opsForValue().get(key);
        return failCount != null && failCount >= MAX_LOGIN_FAILS;
    }

    /**
     * 增加登录失败计数
     */
    private void incrementLoginFail(String usernameOrEmail) {
        String key = RedisKeyUtil.getLoginFailKey(usernameOrEmail);
        redisTemplate.opsForValue().increment(key);
        redisTemplate.expire(key, LOGIN_FAIL_LOCK_TTL, TimeUnit.SECONDS);
    }

    /**
     * 清除登录失败计数
     */
    private void clearLoginFail(String usernameOrEmail) {
        String key = RedisKeyUtil.getLoginFailKey(usernameOrEmail);
        redisTemplate.delete(key);
    }
}